package com.gjy.concurrency.juc;

import com.gjy.util.ListUtil;
import com.google.common.collect.Lists;
import org.junit.jupiter.api.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.LongStream;

/**
 * @author 宫静雨
 * @version 1.0
 * @since 2023-04-21 15:40:47
 */
public class ForkJoinPoolTest {

    @Test
    public void test6() {
        ForkJoinPool pool = new ForkJoinPool();


    }

    @Test
    public void test5() {
        List<Integer> queue = new ArrayList<>();

        ExecutorService pool = Executors.newCachedThreadPool();

        for (int i = 0; i < 1000000; i++) {
            int finalI = i;
            pool.execute(() -> {
                queue.add(finalI);
            });
        }

        System.out.println("queue.size() = " + queue.size());

    }

    @Test
    public void test4() {
        LinkedTransferQueue<Integer> queue = new LinkedTransferQueue<>();

        ExecutorService pool = Executors.newCachedThreadPool();

        for (int i = 0; i < 1000000; i++) {
            int finalI = i;
            pool.execute(() -> {
                queue.add(finalI);
            });
        }

        System.out.println("queue.size() = " + queue.size());

    }

    @Test
    public void test3() {
        ArrayList<Integer> list = Lists.newArrayList();
        for (int i = 0; i < 100; i++) {
            list.add(i);
        }

        List<List<Integer>> lists = ListUtil.averageAssign(list, 10);
        lists.forEach(System.out::println);
    }

    @Test
    public void test2() throws Exception {
        Task1 task1 = new Task1(0L, 1000000000L);

        ForkJoinPool pool = new ForkJoinPool();

        ForkJoinTask<Long> submit = pool.submit(task1);

        Long integer = submit.get();

        System.out.println("integer = " + integer);
    }

    private static final class Task1 extends RecursiveTask<Long> {

        private final Long start;
        private final Long end;

        public Task1(Long start, Long end) {
            this.start = start;
            this.end = end;
        }

        @Override
        protected Long compute() {
            //判断计算范围，如果小于等于5，那么一个线程计算就够了，否则进行分割
            if ((end - start) <= 5) {
                return LongStream.rangeClosed(start, end).sum();
            } else {
                //任务分割
                long middle = (end + start) / 2;
                Task1 task1 = new Task1(start, middle);
                Task1 task2 = new Task1(middle + 1, end);
                //执行
                task1.fork();
                task2.fork();
                //等待返回结果
                return task1.join() + task2.join();
            }
        }
    }

    @Test
    public void test1() throws Exception {

        ForkJoinPool pool = new ForkJoinPool();

        long[] array = {1, 3, 1, 5, 9, 10, 2, 3, 4};
        ForkJoinTask<Void> submit = pool.submit(new Action1(array));

        submit.get();


        System.out.println(Arrays.toString(array));
    }

    private static final class Action1 extends RecursiveAction {

        private static final int THRESHOLD = 1000;

        private final long[] array;
        private final int lo, hi;

        public Action1(long[] array, int lo, int hi) {
            this.array = array;
            this.lo = lo;
            this.hi = hi;
        }

        public Action1(long[] array) {
            this(array, 0, array.length);
        }

        @Override
        protected void compute() {
            if (hi - lo < THRESHOLD) {
                sortSequentially(lo, hi);
            } else {
                int mid = (lo + hi) >>> 1;
                invokeAll(new Action1(array, lo, mid),
                        new Action1(array, mid, hi));
                merge(lo, mid, hi);
            }
        }

        private void sortSequentially(int lo, int hi) {
            Arrays.sort(array, lo, hi);
        }

        private void merge(int lo, int mid, int hi) {
            long[] buf = Arrays.copyOfRange(array, lo, mid);
            for (int i = 0, j = lo, k = mid; i < buf.length; j++) {
                array[j] = (k == hi || buf[i] < array[k]) ? buf[i++] : array[k++];
            }
        }

    }
}
